package com.sijobe.installer;

import com.sijobe.swing.JHyperLink;

import java.awt.EventQueue;

import javax.swing.JFrame;
import java.awt.BorderLayout;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.SwingConstants;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

import java.awt.GridLayout;
import java.awt.Font;
import javax.swing.JCheckBox;

import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JButton;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URI;
import java.util.List;

import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.ComponentOrientation;
import javax.swing.border.LineBorder;

/**
 * Main class that contains the GUI
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author simo_415
 */
public class GuiMain {

   public static final int LOGGING_LEVEL = InstallOutputStream.INFO;

   public static final String FONT_FACE_DEFAULT = "Tahoma";
   public static final int FONT_SIZE_BODY = 16;
   public static final int FONT_SIZE_FOOTER = 9;
   public static final int FRAME_WIDTH = 525;
   public static final int FRAME_HEIGHT = 400;

   public static final String SUPPORT_URL = "http://bit.ly/spcmod";

   JFrame frameModInstaller;
   private JTextField textFieldFilepath;
   private JFileChooser filechooser;
   private JLabel labelInstalling;
   private JButton buttonInstall;
   private JLabel labelOutput;
   private JCheckBox checkboxBackupWorlds;
   private JCheckBox checkboxBackupMinecraftjar;
   private JButton buttonStartMinecraft;
   private JButton advancedButton;
   private static JTextArea TEXTAREA_ADVANCED = new JTextArea();
   private JScrollPane scrollPane;
   private JButton buttonBrowse;

   private boolean installed;

   private ActionHandler n;
   public final String PROJECT;

   /**
    * Launch the application.
    */
   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {

         public void run() {
            try {
               GuiMain window = new GuiMain();
               window.frameModInstaller.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }

   /**
    * Create the application.
    */
   public GuiMain() {
      try {
         System.setOut(new InstallOutputStream(System.out,LOGGING_LEVEL));
      } catch (Exception e) {}
      n = new ActionHandler(this);
      if (n.manifest.getProjectNames().length < 1) {
         System.err.println("The manifest contained within this installer is either missing, corrupt or doesn't contain any projects.");
         System.exit(1);
      }
      PROJECT = n.manifest.getProjectNames()[0];
      initialize();
      //checkMinecraftVersion();
      System.out.println("GUI initialised");
   }

   /**
    * Logs a message to the advanced output textarea
    * 
    * @param message - The message to log
    */
   public static void log(String message) {
      TEXTAREA_ADVANCED.append(message + "\n");
      TEXTAREA_ADVANCED.setCaretPosition(TEXTAREA_ADVANCED.getText().length());
   }

   /**
    * Sends an output error message to the GUI
    * 
    * @param message - The error message
    */
   public void sendError(String message) {
      labelOutput.setForeground(new Color(255, 0, 0));
      labelOutput.setText(message);
      installed = false;
   }

   /**
    * Sends an output success message to the GUI
    * 
    * @param message - The success message
    */
   public void sendSuccessMessage(String message) {
      labelOutput.setForeground(new Color(0, 128, 0));
      labelOutput.setText(message);
      installed = true;
   }

   /**
    * Installs the mod which is contained within the archive
    * 
    * @param install - whether installation is starting or finishing
    */
   public void installMod(boolean install) {
      if (install) {
         // Check that the versions are correct and warn if necessary
         String output = null;
         if ((output = checkMinecraftVersion()) != null) {
            int n = JOptionPane.showConfirmDialog(
                     frameModInstaller,
                     output + "\n\nDo you want to continue installation?",
                     "Version Inconsistency",
                     JOptionPane.YES_NO_OPTION,
                     JOptionPane.WARNING_MESSAGE);
            if (n == 1) {
               return;
            }
         }
         checkboxBackupWorlds.setEnabled(false);
         checkboxBackupMinecraftjar.setEnabled(false);
         buttonBrowse.setEnabled(false);
         buttonInstall.setVisible(false);
         labelInstalling.setVisible(true);
         (new Thread((new Runnable() {
            public void run() {
               try {
                  n.install(PROJECT, n.files, Util.INSTALLBASE, new File(textFieldFilepath.getText()), n.manifest, checkboxBackupMinecraftjar.isSelected(), checkboxBackupWorlds.isSelected());
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }))).start();
      } else {
         labelInstalling.setVisible(false);
         if (installed) {
            buttonStartMinecraft.setVisible(true);
         } else {
            checkboxBackupWorlds.setEnabled(true);
            checkboxBackupMinecraftjar.setEnabled(true);
            buttonBrowse.setEnabled(true);
            buttonInstall.setVisible(true);
         }
      }
   }

   public void browseButtonAction() {
      filechooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
      filechooser.setSelectedFile(new File(textFieldFilepath.getText()));
      int returnVal = filechooser.showOpenDialog(null);

      if (returnVal == JFileChooser.APPROVE_OPTION) {
         File file = filechooser.getSelectedFile();
         textFieldFilepath.setText(file.getAbsolutePath());
         String output = null;
         if ((output = checkMinecraftVersion()) != null) {
            int n = JOptionPane.showConfirmDialog(
                     frameModInstaller,
                     output + "\n\nDo you want to select another location?",
                     "Version Inconsistency",
                     JOptionPane.YES_NO_OPTION,
                     JOptionPane.WARNING_MESSAGE);
            if (n == 0) {
               browseButtonAction();
            }
         }
      }
   }

   /**
    * Checks that the mod can be installed on the version of Minecraft selected
    * by the installer. null is returned when it can be installed, any non-null
    * value returned is an error message that should be displayed to the user. 
    * 
    * @return null when there are no issues, non-null when a problem occurred 
    * with the versions
    */
   public String checkMinecraftVersion() {
      String mcversion = Util.getMinecraftVersion(textFieldFilepath.getText());
      String versions[] = n.manifest.getMinecraftVersions(PROJECT);
      String verstr = "";
      for (int i = 0; i < versions.length; i++) {
         if (mcversion != null && mcversion.equalsIgnoreCase(versions[i])) {
            System.out.println("INFO: Appears to be correct Minecraft (" + mcversion + 
                     ") and mod versions (" + versions[i] + ").");
            return null;
         }
         verstr += versions[i] + ", ";
      }
      verstr = verstr.endsWith(", ") ? verstr.substring(0, verstr.length() - 2) : verstr;
      String message = null;
      if (versions != null && versions.length != 0) {
         if (mcversion == null) {
            message = "Couldn't detect your current Minecraft version, " + 
            "this could be due to Minecraft.jar not existing at " +
            "the specified destination, if you're using an old " +
            "version of Minecraft or an internal error occurred." +
            "\n\nThis mod supports the following versions: " +
            verstr + ". ";
         } else {
            message = "Your current Minecraft version was detected as " + 
            mcversion + ". " + 
            "\nThis mod supports the following versions: " +
            verstr + ". If you continue to install the mod to this " +
            "destination it may not work as expected.";
         }
      }
      System.out.println("WARNING: " + message);
      return message;
   }

   /**
    * Initialize the contents of the frame.
    */
   private void initialize() {
      // Sets the look and feel of the application
      try {
         try {
            LookAndFeelInfo info[] = UIManager.getInstalledLookAndFeels();
            for (int i = 0; i < info.length; i++) {
               if ("Nimbus".equals(info[i].getName())) {
                  UIManager.setLookAndFeel(info[i].getClassName());
                  break;
               }
            }
         } catch (Exception e) {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
         }
      } catch (Exception e) {}

      filechooser = new JFileChooser();

      frameModInstaller = new JFrame();
      frameModInstaller.setResizable(false);
      frameModInstaller.setIconImage(Toolkit.getDefaultToolkit().getImage(GuiMain.class.getResource("/com/sijobe/images/icon.png")));
      frameModInstaller.setTitle(PROJECT + " -  Installation");
      frameModInstaller.setBounds(100, 100, FRAME_WIDTH, FRAME_HEIGHT);
      frameModInstaller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frameModInstaller.getContentPane().setLayout(new BorderLayout(0, 0));

      JPanel panelTop = new JPanel();
      panelTop.setSize(new Dimension(FRAME_WIDTH, 100));
      FlowLayout flowLayout = (FlowLayout) panelTop.getLayout();
      flowLayout.setVgap(0);
      flowLayout.setHgap(0);
      panelTop.setAlignmentY(Component.TOP_ALIGNMENT);
      panelTop.setAlignmentX(Component.LEFT_ALIGNMENT);
      panelTop.setBorder(null);
      frameModInstaller.getContentPane().add(panelTop, BorderLayout.NORTH);

      JLabel labelBanner = new JLabel("");
      labelBanner.setSize(new Dimension(520, 100));
      labelBanner.setVerticalTextPosition(SwingConstants.TOP);
      labelBanner.setVerticalAlignment(SwingConstants.TOP);
      labelBanner.setBorder(null);
      labelBanner.setAlignmentY(Component.TOP_ALIGNMENT);
      labelBanner.setToolTipText(PROJECT);
      labelBanner.setIcon(new ImageIcon(GuiMain.class.getResource("/com/sijobe/images/warning.png")));

      // Added
      File tmp = null;
      BufferedImage bi = null;
      try {
         if ((tmp = Util.getFile(n.manifest.getBanner(PROJECT),n.files)) != null) {
            try {
               bi = Util.scale(javax.imageio.ImageIO.read(tmp),FRAME_WIDTH,100);
            } catch (Exception e) { }
         }
         if (bi != null) {
            labelBanner.setIcon(new ImageIcon(bi));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      // --end added

      panelTop.add(labelBanner);

      JPanel panelMiddle = new JPanel();
      frameModInstaller.getContentPane().add(panelMiddle, BorderLayout.CENTER);
      GridBagLayout gbl_panelMiddle = new GridBagLayout();
      gbl_panelMiddle.columnWidths = new int[]{160, 59, 0, 32, 33, 36, 73};
      gbl_panelMiddle.rowHeights = new int[]{54, 26, 49, 25, 25, 0, 0, 0};
      gbl_panelMiddle.columnWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
      gbl_panelMiddle.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
      panelMiddle.setLayout(gbl_panelMiddle);

      labelOutput = new JLabel("");
      labelOutput.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      //labelOutput.setVisible(false);
      GridBagConstraints gbc_labelOutput = new GridBagConstraints();
      gbc_labelOutput.gridwidth = 7;
      gbc_labelOutput.insets = new Insets(0, 0, 5, 0);
      gbc_labelOutput.gridx = 0;
      gbc_labelOutput.gridy = 0;
      panelMiddle.add(labelOutput, gbc_labelOutput);

      JTextArea labelDescription = new JTextArea(n.manifest.getDescription(PROJECT));
      labelDescription.setBorder(null);
      labelDescription.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
      labelDescription.setWrapStyleWord(true);
      labelDescription.setColumns(35);
      labelDescription.setTabSize(3);
      labelDescription.setLineWrap(true);
      labelDescription.setBackground(new Color(0,0,0,0)/*UIManager.getColor("Panel.background")*/);
      labelDescription.setEditable(false);
      labelDescription.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      GridBagConstraints gbc_labelDescription = new GridBagConstraints();
      gbc_labelDescription.anchor = GridBagConstraints.NORTHWEST;
      gbc_labelDescription.gridwidth = 7;
      gbc_labelDescription.insets = new Insets(0, 0, 5, 0);
      gbc_labelDescription.gridx = 0;
      gbc_labelDescription.gridy = 1;
      panelMiddle.add(labelDescription, gbc_labelDescription);

      String mcdir = "";
      if (Util.getMinecraftDir() != null) {
         mcdir = Util.getMinecraftDir().getAbsolutePath();
      }
      textFieldFilepath = new JTextField();
      textFieldFilepath.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent arg0) {
            browseButtonAction();
         }
      });
      textFieldFilepath.setPreferredSize(new Dimension(370, 40));
      textFieldFilepath.setMinimumSize(new Dimension(380, 40));
      textFieldFilepath.setEditable(false);
      textFieldFilepath.setHorizontalAlignment(SwingConstants.RIGHT);
      textFieldFilepath.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      GridBagConstraints gbc_textFieldFilepath = new GridBagConstraints();
      gbc_textFieldFilepath.fill = GridBagConstraints.HORIZONTAL;
      gbc_textFieldFilepath.anchor = GridBagConstraints.WEST;
      gbc_textFieldFilepath.gridwidth = 5;
      gbc_textFieldFilepath.gridx = 0;
      gbc_textFieldFilepath.gridy = 2;
      panelMiddle.add(textFieldFilepath, gbc_textFieldFilepath);
      textFieldFilepath.setColumns(26);
      textFieldFilepath.setText(mcdir);

      buttonBrowse = new JButton("Browse");
      buttonBrowse.setHorizontalAlignment(SwingConstants.RIGHT);
      buttonBrowse.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      buttonBrowse.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent arg) {
            browseButtonAction();
         }
      });
      GridBagConstraints gbc_buttonBrowse = new GridBagConstraints();
      gbc_buttonBrowse.anchor = GridBagConstraints.EAST;
      gbc_buttonBrowse.gridwidth = 2;
      gbc_buttonBrowse.insets = new Insets(0, 0, 5, 0);
      gbc_buttonBrowse.gridx = 5;
      gbc_buttonBrowse.gridy = 2;
      panelMiddle.add(buttonBrowse, gbc_buttonBrowse);

      checkboxBackupMinecraftjar = new JCheckBox("Backup Minecraft.jar");
      checkboxBackupMinecraftjar.setSelected(true);
      checkboxBackupMinecraftjar.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      GridBagConstraints gbc_checkboxBackupMinecraftjar = new GridBagConstraints();
      gbc_checkboxBackupMinecraftjar.anchor = GridBagConstraints.WEST;
      gbc_checkboxBackupMinecraftjar.insets = new Insets(0, 0, 5, 5);
      gbc_checkboxBackupMinecraftjar.gridx = 0;
      gbc_checkboxBackupMinecraftjar.gridy = 3;
      panelMiddle.add(checkboxBackupMinecraftjar, gbc_checkboxBackupMinecraftjar);

      checkboxBackupWorlds = new JCheckBox("Backup Worlds");
      checkboxBackupWorlds.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      GridBagConstraints gbc_checkboxBackupWorlds = new GridBagConstraints();
      gbc_checkboxBackupWorlds.insets = new Insets(0, 0, 5, 5);
      gbc_checkboxBackupWorlds.anchor = GridBagConstraints.WEST;
      gbc_checkboxBackupWorlds.gridx = 0;
      gbc_checkboxBackupWorlds.gridy = 4;
      panelMiddle.add(checkboxBackupWorlds, gbc_checkboxBackupWorlds);

      buttonInstall = new JButton("Install Version " + n.manifest.getVersion(PROJECT));
      buttonInstall.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent e) {
            installMod(true);
         }
      });
      buttonInstall.setHorizontalAlignment(SwingConstants.RIGHT);
      buttonInstall.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      GridBagConstraints gbc_buttonInstall = new GridBagConstraints();
      gbc_buttonInstall.insets = new Insets(0, 0, 5, 0);
      gbc_buttonInstall.anchor = GridBagConstraints.EAST;
      gbc_buttonInstall.gridwidth = 5;
      gbc_buttonInstall.gridheight = 2;
      gbc_buttonInstall.gridx = 2;
      gbc_buttonInstall.gridy = 3;
      panelMiddle.add(buttonInstall, gbc_buttonInstall);

      labelInstalling = new JLabel("");
      labelInstalling.setHorizontalAlignment(SwingConstants.CENTER);
      labelInstalling.setIcon(new ImageIcon(GuiMain.class.getResource("/com/sijobe/images/loading.gif")));
      labelInstalling.setVisible(false);
      GridBagConstraints gbc_labelInstalling = new GridBagConstraints();
      gbc_labelInstalling.insets = new Insets(0, 0, 5, 0);
      gbc_labelInstalling.anchor = GridBagConstraints.EAST;
      gbc_labelInstalling.gridwidth = 5;
      gbc_labelInstalling.gridheight = 2;
      gbc_labelInstalling.gridx = 2;
      gbc_labelInstalling.gridy = 3;
      panelMiddle.add(labelInstalling,gbc_labelInstalling);

      buttonStartMinecraft = new JButton("Start Minecraft");
      buttonStartMinecraft.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent arg0) {
            n.startMinecraft(new File(textFieldFilepath.getText()));
         }
      });
      buttonStartMinecraft.setHorizontalAlignment(SwingConstants.RIGHT);
      buttonStartMinecraft.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_BODY));
      buttonStartMinecraft.setVisible(false);
      GridBagConstraints gbc_buttonStartMinecraft = new GridBagConstraints();
      gbc_buttonStartMinecraft.insets = new Insets(0, 0, 5, 0);
      gbc_buttonStartMinecraft.anchor = GridBagConstraints.EAST;
      gbc_buttonStartMinecraft.gridwidth = 5;
      gbc_buttonStartMinecraft.gridheight = 2;
      gbc_buttonStartMinecraft.gridx = 2;
      gbc_buttonStartMinecraft.gridy = 3;
      panelMiddle.add(buttonStartMinecraft, gbc_buttonStartMinecraft);
      TEXTAREA_ADVANCED.setMargin(new Insets(0, 0, 0, 0));
      TEXTAREA_ADVANCED.setFont(new Font("Monospaced", Font.PLAIN, 11));
      TEXTAREA_ADVANCED.setBorder(null);
      TEXTAREA_ADVANCED.setAlignmentY(Component.TOP_ALIGNMENT);
      TEXTAREA_ADVANCED.setAlignmentX(Component.LEFT_ALIGNMENT);

      //TEXTAREA_ADVANCED = new JTextArea();
      scrollPane = new JScrollPane(TEXTAREA_ADVANCED); 
      scrollPane.setVisible(false);
      TEXTAREA_ADVANCED.setEditable(false);
      GridBagConstraints gbc_textAreaAdvanced = new GridBagConstraints();
      gbc_textAreaAdvanced.gridheight = 2;
      gbc_textAreaAdvanced.insets = new Insets(0, 0, 5, 0);
      gbc_textAreaAdvanced.gridwidth = 7;
      gbc_textAreaAdvanced.fill = GridBagConstraints.BOTH;
      gbc_textAreaAdvanced.gridx = 0;
      gbc_textAreaAdvanced.gridy = 5;
      panelMiddle.add(scrollPane, gbc_textAreaAdvanced);

      JPanel panelBottom = new JPanel();
      panelBottom.setBorder(new EmptyBorder(2, 0, 2, 0));
      frameModInstaller.getContentPane().add(panelBottom, BorderLayout.SOUTH);
      panelBottom.setLayout(new GridLayout(1, 0, 1, 0));

      // Dynamic link adding
      List links = n.manifest.getFooterLinks(PROJECT);
      for (int i = 0; i < links.size() && i < 4; i++) {
         FooterLink link = (FooterLink)links.get(i);
         if (link == null) {
            continue;
         }
         System.out.println("DEBUG: Adding link " + link.getName() + " - " + link.getValue());
         JHyperLink hyperLink = null;
         if (link.getValue().startsWith("http://")) {
            try {
               hyperLink = new JHyperLink(link.getName(),new URI(link.getValue()));
            } catch (Exception e) {}
         } else {
            hyperLink = new JHyperLink(link.getName(),Util.getFile(link.getValue(),n.files));
         }
         if (hyperLink == null) {
            continue;
         }
         hyperLink.setHorizontalAlignment(SwingConstants.CENTER);
         panelBottom.add(hyperLink);
      }
      // End dynamic links

      advancedButton = new JButton("Advanced >");
      advancedButton.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent arg) {
            if (advancedButton.getText().contains(">")) {
               advancedButton.setText("< Advanced");
               frameModInstaller.setSize(FRAME_WIDTH, FRAME_HEIGHT + 100);
               scrollPane.setVisible(true);
            } else {
               advancedButton.setText("Advanced >");
               frameModInstaller.setSize(FRAME_WIDTH, FRAME_HEIGHT);
               scrollPane.setVisible(false);
            }
         }
      });
      advancedButton.setPreferredSize(new Dimension(25, 15));
      advancedButton.setFont(new Font(FONT_FACE_DEFAULT, Font.PLAIN, FONT_SIZE_FOOTER));
      panelBottom.add(advancedButton);

      JPanel panelLeft = new JPanel();
      frameModInstaller.getContentPane().add(panelLeft, BorderLayout.WEST);

      JPanel panelRight = new JPanel();
      frameModInstaller.getContentPane().add(panelRight, BorderLayout.EAST);

      //JOptionPane.showMessageDialog(frameModInstaller,Util.getMinecraftVersion());
   }

}
